/*
 * JJConnect.java
 *
 * Created on 30 Сентябрь 2007 г., 12:36
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package xmppbot;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smackx.muc.DiscussionHistory;
import org.jivesoftware.smackx.muc.MultiUserChat;

/**
 *
 * @author lian
 */
public class JJConnect
{
    public XMPPConnection Connect;                      // соединение
    public ConnectionConfiguration ConnectConfig;       // конфиг соединения (не используется)
    public String Login;                                // логин
    public String Pass;                                 // пароль
    public String resource;                             // ресурс
    public HashMap mchats = new HashMap();              // HashMap конференций
    public ArrayList mchatsnames = new ArrayList();     // список имён конференций
    public db mysqldb;                                  // база
    public HashMap settings = new HashMap();            // HashMap с настройками
    public HashMap mchatsListeners = new HashMap();
    public HashMap mchatsMsgListeners = new HashMap();
    
    /** Creates a new instance of JJConnect 
     *  Здесь, думаю, всё ясно:
     *  адрес порт...
     */
    public JJConnect (String ServerAdress, int ServerPort, String ServerName, String Login, String Pass, String resource)
    {
        ConnectConfig = new ConnectionConfiguration(ServerAdress, ServerPort, ServerName);
        Connect = new XMPPConnection(ConnectConfig);
        this.Login = Login;
        this.Pass = Pass;
        this.resource = resource;
    }

    /** Creates a new instance of JJConnect 
     *  Здесь, думаю, всё ясно:
     *  адрес порт...
     */
    public JJConnect (String ServerName, String Login, String Pass, String resource)
    {
        Connect = new XMPPConnection(ServerName);
        this.Login = Login;
        this.Pass = Pass;
        this.resource = resource;
    }
    
    /**
     * Возвращает объект JJConnect, но я его практически не использую
     * чаще использую прямое обращение к переменной объекта
     * @return возвращает объект JJConnect
     */
    public XMPPConnection getConnect ()
    {
        return Connect;
    }
    
    /**
     * Подключает к серверу, используя переданные конструктору данные
     */
    public void Connect ()
    {
        try
        {
            Connect.connect ();
        } catch (XMPPException ex)
        {
            ex.printStackTrace();
        }
        
        try
        {
            Connect.login (Login, Pass, resource);
        } catch (XMPPException ex)
        {
            ex.printStackTrace();
        }
        
    }
    
    /**
     * Подключается к конференции и добавляет конференцию(объект MultiUserChat) в mchats и mchatsnames
     * также подключает все нужные листенеры
     * @param user Имя в конференции
     * @param conference JID конференции
     * @return true, если операция выполнена успешно, false, если подключение неудалось
     */
    @SuppressWarnings("unchecked")
    public boolean join (String user, String conference)
    {
        // Создаём объект конференции
        MultiUserChat mchat = new MultiUserChat(Connect, conference);
        DiscussionHistory dhist = new DiscussionHistory();
        dhist.setSeconds (0);
        boolean flag = true;
        try {
            // пробуем заджониться
            mchat.join (user, "", dhist, 500000);
            // если не получмлось ловим ошибку
            // если всё ок добавляем листенеры
            
            // листенер ловит общие сообщения конференции 
            // и общие сообщения сообщения конференции, адресованные боту (botname: msg)
            mchatsMsgListeners.put(conference + "/" + user, new groupMsgCatcher(mchat.getNickname (), Connect, mchat));
            mchat.addMessageListener ((PacketListener) mchatsMsgListeners.get(conference + "/" + user));
            PacketFilter filter = new AndFilter (new PacketTypeFilter(Message.class), new MessageTypeFilter(Message.Type.chat));
            Connect.createPacketCollector (filter);
            // разрешаем ловить сообщения боту только в одном листенере
            boolean globlist;
            // добавляем конференцию в общий список
            mchats.put(conference + "/" + user, mchat);
            mchatsnames.add(conference + "/" + user);
            if (mchats.size() == 1) {
                globlist = true;
            } else {
                globlist = false;
            }
            // листенер ловит приватные сообщения из конференции и личные сообщения боту
            mchatsListeners.put(conference + "/" + user, new privMsgCatcher(mchat.getRoom (), Connect, mchat, globlist));
            Connect.addPacketListener ((PacketListener) mchatsListeners.get(conference + "/" + user), filter);
            System.out.println(conference + "/" + user + " logged in");
        } catch (XMPPException ex) {
            ex.printStackTrace();
            flag = false;
        }
        return flag;
    }
    
    public void leave (String conference) {
        MultiUserChat mchat = (MultiUserChat) mchats.get(conference);
        mchat.leave();
        PacketListener list = (PacketListener) mchatsMsgListeners.get(conference);
        mchatsMsgListeners.remove(conference);
        mchat.removeMessageListener(list);
        list = null;
        list = (PacketListener) mchatsListeners.get(conference);
        mchatsListeners.remove(conference);
        Connect.removePacketListener(list);
        list = null;
        mchat = null;
        mchats.remove(conference);
        mchatsnames.remove(conference);
    }
    
    /**
     * получает или обновляет настройки
     * @return true если ошибок нет, false если есть
     */
    @SuppressWarnings("unchecked")
    public boolean UpdateSettings () throws SQLException {
        boolean flag = true;
        ResultSet rs = null;
        try {
            rs = mysqldb.getStatement().executeQuery("SELECT setting,val FROM settings;");
            while (rs.next()) {
                settings.put(rs.getString("setting"), rs.getString("val"));
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
            flag = false;
            db.killrs(rs); rs = null;
        }
        db.killrs(rs); rs = null;
        return flag;
    }
    
    public void Disconnect ()
    {
        for (int i = 0; i < mchatsnames.size(); i++) {
            leave((String) mchatsnames.get(i));
        }
        Connect.disconnect ();
    }
}
